{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "47c6a657",
   "metadata": {},
   "source": [
    "卷积并非一定是从上到下从左到右的。首先观察一个从上到下的例子（该例子使用了点云数据作为背景）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "de10e0ad",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Microsoft Visual C++ Redistributable is not installed, this may lead to the DLL load failure.\n",
      "It can be downloaded at https://aka.ms/vs/16/release/vc_redist.x64.exe\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torch.nn as nn"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "93492aa6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 输入：4个点，每个点3个坐标 [batch_size=1, channels=1, N=4, 3]\n",
    "x = torch.tensor([\n",
    "    [\n",
    "        [\n",
    "            [1.0, 2.0, 3.0],  # 点1\n",
    "            [4.0, 5.0, 6.0],  # 点2\n",
    "            [7.0, 8.0, 9.0],  # 点3\n",
    "            [10.0, 11.0, 12.0]  # 点4\n",
    "        ]\n",
    "    ]\n",
    "])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "373300e5",
   "metadata": {},
   "source": [
    "这种卷积的运算逻辑如下，卷积的方向实际上由卷积核的SizeShape决定，如果某个维度非1，那么就会进行滑动。\n",
    "输入点1: [x₁, y₁, z₁]\n",
    "卷积核: [w₁, w₂, w₃]  # 宽度方向尺寸为3\n",
    "\n",
    "运算过程:\n",
    "  输出₁ = w₁*x₁ + w₂*y₁ + w₃*z₁\n",
    "  输出₂ = w₁*x₂ + w₂*y₂ + w₃*z₂\n",
    "  ...\n",
    "  输出₄ = w₁*x₄ + w₂*y₄ + w₃*z₄"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "ee328e6f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 1D卷积层：kernel_size=[1, 3]，在宽度方向滑动\n",
    "conv = nn.Conv2d(\n",
    "    in_channels=1,      # 输入通道数\n",
    "    out_channels=1,     # 输出通道数\n",
    "    kernel_size=[1, 3], # 卷积核尺寸\n",
    "    stride=1,           # 步长\n",
    "    padding=0           # 不填充\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "0e0109fc",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 手动设置卷积核权重为 [1, 0, -1]（仅作示例）\n",
    "conv.weight.data = torch.tensor([[[[1.0, 0.0, -1.0]]]])\n",
    "conv.bias.data = torch.tensor([0.0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "e7b25e47",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输入形状: torch.Size([1, 1, 4, 3])\n",
      "输出形状: torch.Size([1, 1, 4, 1])\n",
      "输出值:\n",
      " tensor([[[[-2.],\n",
      "          [-2.],\n",
      "          [-2.],\n",
      "          [-2.]]]], grad_fn=<ConvolutionBackward0>)\n"
     ]
    }
   ],
   "source": [
    "# 执行卷积\n",
    "output = conv(x)\n",
    "print(\"输入形状:\", x.shape)  # [1, 1, 4, 3]\n",
    "print(\"输出形状:\", output.shape)  # [1, 1, 4, 1]\n",
    "print(\"输出值:\\n\", output)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d7caebe1",
   "metadata": {},
   "source": [
    "接下来我们尝试获取水平方向上的特征获取。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "c9746804",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 输入：1张图像，1个通道，尺寸5×5\n",
    "x = torch.randn(1, 1, 5, 5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "32b5a83a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 水平方向卷积：kernel_size=[1, 3]（高度1，宽度3）\n",
    "conv_horizontal = nn.Conv2d(\n",
    "    in_channels=1,\n",
    "    out_channels=1,\n",
    "    kernel_size=[1, 3],  # 只在宽度方向滑动\n",
    "    stride=1,\n",
    "    padding=0\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "7cfd1c15",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输入形状: torch.Size([1, 1, 5, 5])\n",
      "输出形状: torch.Size([1, 1, 5, 3])\n"
     ]
    }
   ],
   "source": [
    "output = conv_horizontal(x)\n",
    "print(\"输入形状:\", x.shape)      # [1, 1, 5, 5]\n",
    "print(\"输出形状:\", output.shape)  # [1, 1, 5, 3]（高度不变，宽度减少2）"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "027984fd",
   "metadata": {},
   "source": [
    "我们再次确认一个垂直方向卷积的操作。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "27e791ed",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 垂直方向卷积：kernel_size=[3, 1]（高度3，宽度1）\n",
    "conv_vertical = nn.Conv2d(\n",
    "    in_channels=1,\n",
    "    out_channels=1,\n",
    "    kernel_size=[3, 1],  # 只在高度方向滑动\n",
    "    stride=1,\n",
    "    padding=0\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "77c82010",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输入形状: torch.Size([1, 1, 5, 5])\n",
      "输出形状: torch.Size([1, 1, 3, 5])\n"
     ]
    }
   ],
   "source": [
    "output = conv_vertical(x)\n",
    "print(\"输入形状:\", x.shape)      # [1, 1, 5, 5]\n",
    "print(\"输出形状:\", output.shape)  # [1, 1, 3, 5]（宽度不变，高度减少2）"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "my_env",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
